package org.jeecg.modules.system.aspect;

import com.gaoh.modules.util.BaseUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * @author gaoh
 * @version 1.0
 * @date 2019/12/05
 * <p>
 * 用于打印日志
 */
@Aspect
@Component
@Slf4j
public class ShowOperationAspect implements Ordered {

    /**
     * Controller层切点
     */
    @Pointcut("execution(* org.jeecg.modules.*.controller..*.*(..))")
    public void controllerPointcut() {
    }


    /**
     * Service层切点 异常切点
     */
    @Pointcut("execution(* org.jeecg.modules.*.service..*.*(..))")
    public void servicePointcut() {
    }

    /**
     * 实现org.springframework.core.Ordered接口来定义order的顺序，order的值越小，越先被执行8
     */
    @Override
    public int getOrder() {
        return 2;
    }

    /**
     * 环绕通知 用于拦截 Controller层  参数的基本信息
     *
     * @param point
     * @throws Throwable
     */
    @Around("controllerPointcut()")
    public Object doAround(ProceedingJoinPoint point) throws Throwable {
        long beginTime = System.currentTimeMillis();
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        //方法的签名
        MethodSignature methodSignature = ((MethodSignature) point.getSignature());

        //切入的目标类
        Object target = point.getTarget();
        RequestMapping annotation = target.getClass().getAnnotation(RequestMapping.class);
        String url = "";
        if (annotation != null && (annotation.value().length > 0)) {
            url = annotation.value()[0];
        }

        if (methodSignature.getMethod().getAnnotation(RequestMapping.class) != null) {
            //请求的Url
            String[] val = methodSignature.getMethod().getAnnotation(RequestMapping.class).value();
            log.info("请求路径:" + url + val[0]);
        }

        String methodName = methodSignature.getMethod().getName();
        log.info("目标方法名:{}", methodName);

        //region
        //************************请求参数打印****************************
       /* //参数名称
        String[] parameterNames = methodSignature.getParameterNames();
        //其他请求参数
        Map<String, String> paramMap = new HashMap<>(6);
        Object[] args = point.getArgs();
        if (args != null) {
            for (int i = 0; i < args.length; ++i) {
                Object o = args[i];
                if (o instanceof MultipartFile || o instanceof MultipartFile[]) {
                    continue;
                }
                if (o instanceof HttpServletRequest) {
                    Enumeration en = request.getParameterNames();
                    Map<String, String> map = new HashMap<>();
                    while (en.hasMoreElements()) {
                        String name = en.nextElement().toString();
                        String value = request.getParameter(name);
                        map.put(name, value);
                    }
                    if (map.size() > 0) {
                        log.info("HttpServletRequest请求参数:" + map);
                    }
                    continue;
                }
                if (o instanceof Serializable) {
                    if (o instanceof String) {
                        paramMap.put(parameterNames[i], JSONObject.toJSONString(o));
                    } else if (o instanceof Integer) {
                        paramMap.put(parameterNames[i], JSONObject.toJSONString(o));
                    } else {
                        log.info("实体请求参数:" + JSONObject.toJSONString(o));
                    }
                }
            }
        }
        if (paramMap.size() > 0) {
            log.info("其他请求参数:" + paramMap.toString());
        }*/
        //***************************************请求参数打印**********************************
        // endregion
        //获取返回的结果
        Object proceed = null;
        try {
            proceed = point.proceed(point.getArgs());
        } catch (Exception e) {
            e.printStackTrace();
            log.info(e.getMessage());
        }

        log.info("执行时间:{}ms", System.currentTimeMillis() - beginTime);
        return proceed;
    }

    /**
     * 异常通知 用于拦截service
     *
     * @param point
     * @param e
     */
    @AfterThrowing(pointcut = "servicePointcut()", throwing = "e")
    public void doAfterThrowing(JoinPoint point, Throwable e) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        //获取用户请求方法的参数并序列化为JSON格式字符串
        StringBuilder params = new StringBuilder();
        Object args[] = point.getArgs();
        if (args != null && args.length > 0) {
            for (int i = 0; i < args.length; i++) {
                params.append(args[i].toString()).append(";");
            }
        }
//        String memo = "";
        String exceptionMethod = point.getTarget().getClass().getName() + "." + point.getSignature().getName() + "()";
        try {
            MethodSignature methodSignature = (MethodSignature) point.getSignature();
            log.info("==============================异常通知开始==============================");
            log.info("请求IP：{}", new Object[]{BaseUtils.analysisIP(request)}); // 获取请求IP
            log.info("请求方法：{}", new Object[]{exceptionMethod});
            log.info("请求参数：{}", new Object[]{params.toString()});
            log.info("==============================异常通知结束==============================");
        } catch (Exception ex) {
            log.error(ex.getMessage());
        }
    }
}
